/*
 * Group 3, User Interface Programming II (vt11)
 * Pooya | Flora | Monica | Can
 */
package vical.model;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

/**
 * The model for the month view.
 * 
 * @author Can
 * @author Pooya
 */
public class MonthModel {

    private List<DayCardModel> dayCardModels;
    private int month;
    private int year;
    private int firstDayOfWeek;

    public MonthModel() {
        // Set current month as default month
        Calendar today = Calendar.getInstance();
        this.month = today.get(Calendar.MONTH);
        this.year = today.get(Calendar.YEAR);
        firstDayOfWeek = Calendar.MONDAY;
        initMonthModel();
    }

    public MonthModel(int year, int month) {
        this.year = year;
        this.month = month;
        firstDayOfWeek = Calendar.MONDAY;
        initMonthModel();
    }

    public MonthModel(int month, int year, int firstDayOfWeek) {
        this.month = month;
        this.year = year;
        this.firstDayOfWeek = firstDayOfWeek;
        initMonthModel();
    }

    /**
     * The algorithm of generate dayCardModels are written by Pooya
     */
    private void initMonthModel() {
        dayCardModels = new ArrayList<DayCardModel>();

        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month);
        calendar.setFirstDayOfWeek(getFirstDayOfWeek());
        calendar.set(Calendar.DAY_OF_MONTH, 1);

        int total; // Total amount of days in each part
        // Calculate how many days of previous month should be shown
        int withDraw = Calendar.SUNDAY - calendar.get(Calendar.DAY_OF_WEEK) + 1;
        // Since java consider Sunday as the first day of the week
        // a rotation is needed, so we consider Sunday as 6 withdraw days
        withDraw = withDraw == 1 ? -6 : withDraw;
        // If first day is not Monday ...
        if (withDraw != 0) {
            // Subtract withDraw from the first of current month
            calendar.add(Calendar.DAY_OF_MONTH, withDraw);
            // Calculate the number of days should be added to this month from previous one
            total = calendar.getActualMaximum(Calendar.DAY_OF_MONTH) - calendar.get(Calendar.DAY_OF_MONTH) + 1;
            for (int i = 0; i < total; i++) {
                dayCardModels.add(new DayCardModel(calendar, DayCardModel.DayType.OtherDays));
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
        }

        // Calculate amount of days in the current month
        total = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
        for (int i = 0; i < total; i++) {
            dayCardModels.add(new DayCardModel(calendar, DayCardModel.DayType.RegularDay));
            calendar.add(Calendar.DAY_OF_MONTH, 1);
        }

        // Calculate the number of days that should be added to this month from next one
        total = Calendar.SATURDAY - calendar.get(Calendar.DAY_OF_WEEK) + 1;
        // Since java considers Sunday as the first day of the week
        total = total == 7 ? 0 : total;
        // If the last day is not Sunday ...
        if (total != 6) {
            for (int i = 0; i <= total; i++) {
                dayCardModels.add(new DayCardModel(calendar, DayCardModel.DayType.OtherDays));
                calendar.add(Calendar.DAY_OF_MONTH, 1);
            }
        }

    }

    /**
     * Returns all available days in a specific month
     * including some days of previous and next month
     * @return
     */
    public List<DayCardModel> getDayCardModels() {
        return dayCardModels;
    }

    public int getRowsCount() {
        if (dayCardModels.size() < getColumnsCount() * 5 + 1) { // Some months have 6 weeks
            return 5;
        } else {
            return 6;
        }
    }

    public int getColumnsCount() {
        return 7;   // seven days in a week
    }

    public int getFirstDayOfWeek() {
        return firstDayOfWeek;
    }

    public void setFirstDayOfWeek(int firstDayOfWeek) {
        this.firstDayOfWeek = firstDayOfWeek;
    }

    public int getMonth() {
        return month;
    }

    public String getMonthString() {
        // TODO: language
        String[] monthName = {"January", "February",
            "March", "April", "May", "June", "July",
            "August", "September", "October", "November",
            "December"};
        return monthName[month];
    }

    public int getYear() {
        return year;
    }

    public void setCategoriesFilter(List<String> categories) {
        for (DayCardModel dayCardModel : dayCardModels) {
            dayCardModel.setCategoriesFilter(categories);
        }
    }

    public void setPrioritiesFilter(ArrayList<String> priorities) {
        for (DayCardModel dayCardModel : dayCardModels) {
            dayCardModel.setPrioritiesFilter(priorities);
        }
    }

    public void nextMonth() {
        if (month == 11) {
            year++;
            month = 0;
        } else {
            month++;
        }
        initMonthModel();
    }

    public void previousMonth() {
        if (month == 0) {
            year--;
            month = 11;
        } else {
            month--;
        }
        initMonthModel();
    }

    public void jumpToDate(int year, int month) {
        this.year = year;
        this.month = month;
        initMonthModel();
    }
}
